﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Web;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Com.FastSearch.SharePoint.Interfaces;
using Com.FastSearch.Utils;
using Microsoft.SharePoint;

namespace Com.FastSearch.SharePoint.WebControls.ESPSearchWebParts.UI.Editors
{
    internal class ESPWeightedNavigatorEditorPart : EditorPart
    {
        #region Constants

        internal const string NAVIGATOR_LABEL = "Navigator";
        internal const string NAVIGATOR_TOOLTIP = "Choose a navigator to display.";

        internal const string NAVIGATOR_SCOPE_LABEL = "Scope";
        internal const string NAVIGATOR_SCOPE_TOOLTIP = "The xml scope to aggregate the navigator over.";

        internal const string NUMBER_OF_MODIFIERS_LABEL = "Number of items";
        internal const string NUMBER_OF_MODIFIERS_TOOLTIP = "The number of items to show for the navigator initially.";

        internal const string SHOW_MORE_LINK_LABEL = "Show more link";
        internal const string SHOW_MORE_LINK_TOOLTIP = "Show a link to more items if all are not shown initially.";

        internal const string RENDER_PERCENTAGE_AS_BAR_LABEL = "Render Percentage as Bar";
        internal const string RENDER_PERCENTAGE_AS_BAR_TOOLTIP = "Render the percentage value as Bar Chart if percentage output is used.";

        internal const string COUNT_STRATEGY_LABEL = "Count format";
        internal const string COUNT_STRATEGY_TOOLTIP = "How to represent the number of hits for each navigator item. If a navigator isn't aggregated over the entire result-set, counts and percentages may be inaccurate.";

        internal const string COUNT_STRATEGY_COUNT_FALLBACK_TO_PERCENTAGE = "Numeric or percentage";
        internal const string COUNT_STRATEGY_COUNT_FALLBACK_TO_NONE = "Numeric or none";
        internal const string COUNT_STRATEGY_ALWAYS_COUNT = "Always numeric";
        internal const string COUNT_STRATEGY_ALWAYS_PERCENTAGE = "Always percentage";
        internal const string COUNT_STRATEGY_NONE = "No count";

        internal const string USER_SECTION_HEAD_CLASS = "UserSectionHead";
        internal const string USER_SECTION_BODY_CLASS = "UserSectionBody";
        internal const string USER_CONTROL_GROUP_CLASS = "UserControlGroup";
        internal const string USER_DOTTED_LINE_CLASS = "UserDottedLine";

        internal const string SCRIPT_RENDERED_KEY = "ESPNavigatorEditorPartScriptRendered";

        #endregion

        #region Class variables

        private readonly string _view;
        private IDictionary<string, IESPNavigatorDefinition> _navigators;

        private DropDownList _navigatorList;
        private TextBox _navigatorScope;
        private CheckBox _showMoreLink;
        private CheckBox _renderAsBar;
        private TextBox _numberOfModifiers;
        private DropDownList _countStrategyList;
        private HtmlTableRow _scopeRow;

        #endregion

        public ESPWeightedNavigatorEditorPart(string view)
        {
            _view = view;
        }

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            try
            {
                IESPSearchManager sm = GetSearchManager();
                _navigators = sm.GetNavigatorsForView(_view);
            }
            catch (Exception)
            {
                _navigators = new Dictionary<string, IESPNavigatorDefinition>(0);
            }
        }

        public override bool ApplyChanges()
        {
            ESPWeightedNavigator navigator = WebPartToEdit as ESPWeightedNavigator;
            if (navigator != null)
            {
                EnsureChildControls();
                IESPNavigatorDefinition navDef = _navigators[_navigatorList.SelectedValue];
                navigator.NavigatorName = _navigatorList.SelectedValue;
                if (navDef != null && navDef.IsScopeNavigator)
                {
                    navigator.NavigatorScope = _navigatorScope.Text;
                }
                navigator.ShowMoreLink = _showMoreLink.Checked;
                navigator.RenderPercentageAsBar = _renderAsBar.Checked;

                try
                {
                    navigator.NumberOfModifiers = Convert.ToInt32(_numberOfModifiers.Text);
                }
                catch
                {
                    _numberOfModifiers.Text = Convert.ToString(navigator.NumberOfModifiers);
                    return false;
                }
                navigator.Count = (ESPWeightedNavigator.CountStrategy) _countStrategyList.SelectedIndex;
            }

            return (navigator != null);
        }

        public override void SyncChanges()
        {
            ESPWeightedNavigator navigator = WebPartToEdit as ESPWeightedNavigator;
            if (navigator != null)
            {
                EnsureChildControls();
                _navigatorList.SelectedValue = navigator.NavigatorName;
                _navigatorScope.Text = navigator.NavigatorScope;
                _showMoreLink.Checked = navigator.ShowMoreLink;
                _renderAsBar.Checked = navigator.RenderPercentageAsBar;
                _numberOfModifiers.Text = Convert.ToString(navigator.NumberOfModifiers);
                _countStrategyList.SelectedIndex = (int) navigator.Count;
                bool isScopeNavigator = false;
                //if (_navigators[_navigatorList.SelectedValue] != null)
                if (_navigators.ContainsKey(_navigatorList.SelectedValue))
                {
                    isScopeNavigator = _navigators[_navigatorList.SelectedValue].IsScopeNavigator;
                }
                _scopeRow.Attributes["style"] = isScopeNavigator ? (isIE() ? "display:block;" : "display:table-row;") : "display:none;";
            }
        }

        protected override void CreateChildControls()
        {
            HtmlTable table = new HtmlTable();
            AddConfigurationRow(table, NAVIGATOR_LABEL, NAVIGATOR_TOOLTIP, _navigatorList = BuildNavigatorList());
            _scopeRow = AddConfigurationRow(table, NAVIGATOR_SCOPE_LABEL, NAVIGATOR_SCOPE_TOOLTIP, _navigatorScope = BuildNavigatorScope());
            AddConfigurationRow(table, NUMBER_OF_MODIFIERS_LABEL, NUMBER_OF_MODIFIERS_TOOLTIP, _numberOfModifiers = BuildNumberOfModifiers());
            AddConfigurationRow(table, null, null, _showMoreLink = BuildShowMoreLink());
            AddConfigurationRow(table, null, null, _renderAsBar = BuildRenderBarLink());
            AddConfigurationRow(table, COUNT_STRATEGY_LABEL, COUNT_STRATEGY_TOOLTIP, _countStrategyList = BuildCountStrategyList());
            Controls.Add(table);
            _scopeRow.Attributes["id"] = ID + "scopeRow";
            _navigatorList.Attributes["onchange"] = "checkIfScopeNavigatorSelected(this.value, '" + _scopeRow.Attributes["id"] + "');";
        }

        internal static HtmlTableRow AddConfigurationRow(HtmlTable table, string label, string tooltip, Control control)
        {
            HtmlTableRow row;
            HtmlTableCell cell;
            HtmlControl header;
            HtmlControl body;
            HtmlControl controlGroup;
            table.Controls.Add(row = new HtmlTableRow());
            row.Controls.Add(cell = new HtmlTableCell());
            if (label != null && tooltip != null)
            {
                cell.Controls.Add(header = CreateDiv(USER_SECTION_HEAD_CLASS));
                header.Controls.Add(CreateLabel(label, tooltip));
                cell.Controls.Add(body = CreateDiv(USER_SECTION_BODY_CLASS));
                body.Controls.Add(controlGroup = CreateDiv(USER_CONTROL_GROUP_CLASS));
                controlGroup.Controls.Add(control);
            }
            else
            {
                cell.Controls.Add(body = CreateDiv(USER_SECTION_HEAD_CLASS));
                body.Controls.Add(control);
            }
            cell.Controls.Add(CreateDiv(USER_DOTTED_LINE_CLASS));
            return row;
        }

        internal static HtmlControl CreateDiv(string styleClass)
        {
            HtmlControl body = new HtmlGenericControl("div");
            body.Attributes["class"] = styleClass;
            return body;
        }

        internal DropDownList BuildNavigatorList()
        {
            DropDownList navigatorList = new DropDownList();
            foreach (IESPNavigatorDefinition navigator in _navigators.Values)
            {
                navigatorList.Items.Add(new ListItem(navigator.DisplayName, navigator.Name));
            }
            if (navigatorList.Items.Count > 0)
            {
                navigatorList.SelectedIndex = 0;
            }
            return navigatorList;
        }

        internal static TextBox BuildNavigatorScope()
        {
            TextBox navigatorScope = new TextBox();
            navigatorScope.MaxLength = 20;
            navigatorScope.Width = 120;
            return navigatorScope;
        }

        internal static TextBox BuildNumberOfModifiers()
        {
            TextBox numberOfModifiers = new TextBox();
            numberOfModifiers.MaxLength = 5;
            numberOfModifiers.Width = 30;
            return numberOfModifiers;
        }

        internal static CheckBox BuildShowMoreLink()
        {
            CheckBox showMoreLink = new CheckBox();
            showMoreLink.Text = SHOW_MORE_LINK_LABEL;
            showMoreLink.ToolTip = SHOW_MORE_LINK_TOOLTIP;
            return showMoreLink;
        }

        internal static CheckBox BuildRenderBarLink()
        {
            CheckBox renderAsBar = new CheckBox();
            renderAsBar.Text = RENDER_PERCENTAGE_AS_BAR_LABEL;
            renderAsBar.ToolTip = RENDER_PERCENTAGE_AS_BAR_TOOLTIP;
            return renderAsBar;
        }

        internal static DropDownList BuildCountStrategyList()
        {
            DropDownList countStrategyList = new DropDownList();
            countStrategyList.Items.Add(new ListItem(COUNT_STRATEGY_COUNT_FALLBACK_TO_PERCENTAGE, ESPWeightedNavigator.CountStrategy.CountFallbackToPercentage.ToString()));
            countStrategyList.Items.Add(new ListItem(COUNT_STRATEGY_COUNT_FALLBACK_TO_NONE, ESPWeightedNavigator.CountStrategy.CountFallbackToNone.ToString()));
            countStrategyList.Items.Add(new ListItem(COUNT_STRATEGY_ALWAYS_COUNT, ESPWeightedNavigator.CountStrategy.AlwaysCount.ToString()));
            countStrategyList.Items.Add(new ListItem(COUNT_STRATEGY_ALWAYS_PERCENTAGE, ESPWeightedNavigator.CountStrategy.AlwaysPercentage.ToString()));
            countStrategyList.Items.Add(new ListItem(COUNT_STRATEGY_NONE, ESPWeightedNavigator.CountStrategy.None.ToString()));
            if (countStrategyList.Items.Count > 0)
            {
                countStrategyList.SelectedIndex = 0;
            }
            return countStrategyList;
        }

        internal static Label CreateLabel(string labelText, string toolTip)
        {
            Label label = new Label();
            label.Text = labelText;
            label.ToolTip = toolTip;
            return label;
        }

        internal Label CreateErrorMessage(string message)
        {
            Label errorMessage = new Label();
            errorMessage.Text = message;
            errorMessage.ApplyStyle(Zone.ErrorStyle);
            return errorMessage;
        }
        /*
        internal static IESPSearchManager GetSearchManager()
        {
            IESPSearchManagerFactory fact = SimpleFactoryManager<IESPSearchManagerFactory>.Factory;
            return fact.Create(SPContext.Current.Site.WebApplication);
        }*/

        internal IESPSearchManager GetSearchManager()
        {
            IESPSearchManagerFactory fact = SimpleFactoryManager<IESPSearchManagerFactory>.Factory;                        
            // If a custom esp connection shall be used            
            ESPWeightedNavigator espConf = WebPartToEdit as ESPWeightedNavigator;            
            if (espConf != null && espConf.SearchRequest.ESPConnection != null)
            {
                return fact.Create(espConf.SearchRequest.ESPConnection);                
            }
            return fact.Create(SPContext.Current.Site.WebApplication);
        }


        #region WebControl members

        protected override void Render(HtmlTextWriter writer)
        {
            try
            {
                EnsureChildControls();
                if (HttpContext.Current.Items[SCRIPT_RENDERED_KEY] == null)
                {
                    RenderScripts(writer);
                    HttpContext.Current.Items[SCRIPT_RENDERED_KEY] = true;
                }
            }
            catch (Exception ex)
            {
                Controls.Add(new LiteralControl(ex.Message + ". " + ex.StackTrace));
            }
            base.Render(writer);
        }

        private void RenderScripts(TextWriter writer)
        {
            writer.WriteLine("<script type=\"text/javascript\">");
            writer.WriteLine("function checkIfScopeNavigatorSelected(navigator, scopeRowId) {");
            writer.WriteLine("    var row = document.getElementById(scopeRowId);");
            writer.WriteLine("    if (row) {");
            writer.WriteLine("        row.style.display = isScopeNavigator(navigator) ? '" + (isIE() ? "block" : "table-row") + "' : 'none';");
            writer.WriteLine("    }");
            writer.WriteLine("}");
            writer.WriteLine("function isScopeNavigator(navigator) {");
            writer.WriteLine("    switch (navigator) {");
            foreach (IESPNavigatorDefinition navigator in _navigators.Values)
            {
                writer.WriteLine("        case '" + navigator.Name + "':");
                writer.WriteLine("            return " + navigator.IsScopeNavigator.ToString().ToLower() + ";");
            }
            writer.WriteLine("        default:");
            writer.WriteLine("            return false;");
            writer.WriteLine("    }");
            writer.WriteLine("}");
            writer.WriteLine("</script>");
        }

        internal bool isIE()
        {
            return Page.Request.UserAgent != null && Page.Request.UserAgent.IndexOf("MSIE") >= 0;
        }

        #endregion
    }
}